#ifndef CTRL_PACKAGE_CONTROLLER_HPP
#define CTRL_PACKAGE_CONTROLLER_HPP

#include "Ctrl/CtrlConfig.hpp"
#include "Model/Package.hpp"
#include "Model/Requirement.hpp"
#include <boost/signal.hpp>

namespace Ctrl
{

/// @ingroup Ctrl
/// @brief It provides the signals to announce various events related to package operations on the model.
class CTRL_API PackageController
{
public:
	typedef boost::signal< void (Model::Package*)> PackageSelectionSlot;
	typedef boost::signal< void (Model::Package*, Model::Package*)> NewPackageAddedSlot;
	typedef boost::signal< void (Model::Package*, Model::Package*)> PackageRemovedSlot;
	typedef boost::signal< void (Model::Package*, Model::Requirement*)> RootRequirementAddedSlot;
	typedef boost::signal< void (Model::Package*, Model::Requirement*)> RootRequirementRemovedSlot;

public:
	/// @brief It binds the specified slot to the current package change event.
	void subscribeToCurrentPackageChanged( const PackageSelectionSlot::slot_type& slot);
	/// @brief It binds the specified slot to the package removal event.
	void subscribeToPackageRemoved( const PackageRemovedSlot::slot_type& slot);
	/// @brief It binds the specified slot to the package creation event.
	void subscribeToNewPackageAdded( const NewPackageAddedSlot::slot_type& slot);
	/// @brief It binds the specified slot to the root requirement creation event.
	void subscribeToRootRequirementAdded( const RootRequirementAddedSlot::slot_type& slot);
	/// @brief It binds the specified slot to the root requirement removal event.
	void subscribeToRootRequirementRemoved( const RootRequirementRemovedSlot::slot_type& slot);

	/// @brief It sets the current package and signals the current package change event.
	/// @param pNewCurrentPackage the new current package to be set. If NULL, it means that there is no current package.
	void setCurrentPackage( Model::Package* pNewCurrentPackage);

	/// @brief It gets the current package.
	/// @{
	Model::Package* currentPackage() { return pCurrentPackage_; }
	const Model::Package* currentPackage() const { return pCurrentPackage_; }
	/// @}

	/// @brief It emits the signal announcing the package was removed.
	/// @param pParentPackage the parent package which lost the child.
	/// @param pRemovedPackage the package that was removed.
	void announcePackageRemoved( Model::Package* pParentPackage, Model::Package* pRemovedPackage);

	/// @brief It announces that a package was created.
	/// @param pParentPackage the parent of the newly created package.
	/// @param pNewPackage the newly created package.
	void announceNewPackageAdded( Model::Package* pParentPackage, Model::Package* pNewPackage);

	/// @brief It announces that a root requirement was added to the specified package.
	/// @param pPackage the package containing the new root requirement.
	/// @param pAddedRequirement the requirement that was added.
	void announceRootRequirementAdded( Model::Package* pPackage, Model::Requirement* pAddedRequirement);

	/// @brief It announces that a root requirement was removed from the specified package.
	/// @param pPackage the package the root requirement was removed from.
	/// @param pRemovedRequirement the requirement that was removed.
	void announceRootRequirementRemoved( Model::Package* pPackage, Model::Requirement* pRemovedRequirement);

private:
	Model::Package* pCurrentPackage_;

protected:
	PackageSelectionSlot onCurrentPackageChanged_;
	PackageRemovedSlot onPackageRemoved_;
	NewPackageAddedSlot onPackageAdded_;
	RootRequirementAddedSlot onRootRequirementAdded_;
	RootRequirementRemovedSlot onRootRequirementRemoved_;
};

} // namespace Ctrl

#endif // CTRL_PACKAGE_CONTROLLER_HPP
